{{define "Title"}}Traces - appdash{{end}}

{{define "Main"}}

<!-- Styling for the import-json button & menu -->
<style>
  #top-right-btns {
    margin-top: 25px;
  }
  // Offset for the checkbox because it's not actually vertically aligned with
  // the text.
  .trace-checkbox {
    // This doesn't fix the issue:
    //vertical-align: middle;
    position: relative;
    top: 2px;
  }
</style>

<!-- Top-Right Menu -->
<div class="btn-group pull-right" role="group" aria-label="..." id="top-right-btns">
  <!-- Import JSON button -->
  <button class="btn btn-default" type="button" id="import-json"
    data-toggle="collapse" data-target="#import-json-menu"
    title="import JSON traces directly into Appdash">Import JSON</button>

  <!-- Traces options menu -->
  <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false" title="view options for multiple selected traces">
    Traces <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" role="menu">
    <li><a href="#" id="toggle-selection" title="select/deselect all traces">Toggle Selection</a></li>
    <li><a id="export-to-json" title="copy the selected traces to the clipboard as JSON data">Export Selected</a></li>
    <li><a href="#" id="aggregate-view" title="view the aggregated data of the selected traces">Aggregate View</a></li>
  </ul>
</div>

<!-- page title -->
<h1>Traces</h1>

{{template "ImportExport" dict "ID" "import-json-menu" "Action" "Import JSON" "Title" "Import a JSON trace by pasting it below:"}}

<!-- TextArea (non-Flash) fallback for Copy+Paste of JSON traces -->
{{template "ImportExport" dict "ID" "export-json-menu" "Title" "Use ctrl+c or command+c to copy the JSON traces below:"}}

<ul class="list-unstyled">
  {{range .Traces}}
    {{if (call $.Visible .)}}
      <li>
        <input type="checkbox" class="trace-checkbox" checked="yes"
        data-json-trace="{{.String}}">
        <a href="{{urlToTrace .Span.ID.Trace}}">{{.Span.ID.Trace}}</a>

        <ul class="traces">
          <li class="trace" id="span-{{.Span.ID.Span}}">
            {{if .Name}}
            <strong title="{{.ID}}">{{.Name}}</strong>
            {{else}}
            <strong title="{{.ID}}">{{.ID.Span}}</strong>
            {{end}}

            {{if .Span.Annotations}}
            <table class="table table-condensed table-striped">
              {{range (filterAnnotations .Span.Annotations)}}
                {{if .Important}}
                  <tr><th>{{.Key}}</th><td>{{str .Value}}</td></tr>
                {{end}}
              {{end}}
            </table>
            {{end}}
          </li>
        </ul>
      </li>
    {{end}}
  {{end}}
</ul>

<script type="text/javascript">
  // Bindings for the import-json menu.
  (function() {
    // Initialize to avoid showing on first .collapse("hide") call.
    $("#export-json-menu").collapse({toggle: false});
    $("#import-json-menu").collapse({toggle: false});

    // When the export-json-menu is shown we want to hide the import json menu
    // so it takes its place.
    $("#export-json-menu").on('show.bs.collapse', function () {
        $("#import-json-menu").collapse("hide");
    })
    // And vice-versa for the other button:
    $("#import-json").click(function() {
        $("#export-json-menu").collapse("hide");
    });

    // Upon completion of the import form, we POST the JSON trace data up to
    // the "/traces/upload" URL and reload the page to display the new trace.
    $("#import-json-menu .action").click(function() {
      // Trim whitespace to ensure the user pasted something (plus, the server
      // doesn't care about whitespace).
      var data = $("#import-json-menu .textarea").val();
      if(!data || data.trim().length == 0) {
        alert("Please input a valid JSON Trace!");
        return;
      }

      // Upload the trace, refreshing page upon completion.
      $.post("/traces/upload", data)
        .done(function() { location.reload() })
        .fail(function(xhr, textStatus, errorThrown) {
          alert("error: " + xhr.responseText);
        })
      });
    })();

  // Bindings for the traces options menu.
  (function() {
    // selected returns an array of the parsed JSON trace data for each selected
    // trace.
    var selected = function() {
      var traces = [];
      $(".trace-checkbox").each(function(i, e) {
        if($(this).prop("checked")) {
          var j = $(this).attr("data-json-trace");
          traces.push($.parseJSON(j));
        }
      });
      return traces;
    }

    // Export Selected button.
    var exportToJSON = new ZeroClipboard($("#export-to-json"));
    exportToJSON.on("copy", function(e) {
      var sel = selected();
      if(sel.length == 0) {
        return;
      }
      // Note: 2 is the indention level.
      exportToJSON.setText(JSON.stringify(sel, null, 2));
      alert(sel.length + " JSON traces copied to clipboard.")
    });

    // On any ZeroClipboard error (primarily when Flash is not available) we
    // fallback to using the standard textarea.
    exportToJSON.on("error", function(e) {
      exportToJSON.destroy()
      $("#export-to-json").click(function() {
        $("#export-json-menu").collapse("show");

        var sel = selected();
        if(sel.length == 0) {
          return;
        }
        $("#export-json-menu .textarea").val(JSON.stringify(sel, null, 2));
        $("#export-json-menu .textarea").focus().select();
      });
    });

    // Toggle Selection button.
    var checked = true;
    $("#toggle-selection").click(function(e) {
      e.preventDefault();
      checked = !checked;
      $(".trace-checkbox").prop("checked", checked);
    });

    // Aggregate View button.
    $("#aggregate-view").click(function(e) {
      e.preventDefault();
      var sel = selected();

      // If we've selected everything, avoid sending a very long URL query
      // parameter by just going straight to /aggregate which, by default, shows
      // aggregated data for all traces.
      if(sel.length == $(".trace-checkbox").length) {
        window.location.href = {{.BaseURL.String}} + "aggregate";
        return;
      }

      // Send the preceding POST request with the IDs we are interested in
      // viewing, and then GET the /aggregate page.
      var ids = [];
      $.each(sel, function(i, trace) {
        ids.push(trace.ID.Trace);
      });
      window.location.href = {{.BaseURL.String}} + "aggregate?selection=" + ids.join();
    });
  })();
</script>

{{end}}
